package com.atguigu.gmall.rabbit.config;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.rabbit.entity.GmallCorrelationData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

/**
 * 自定义应答实现类
 *
 *      接收交换机应答
 *      接收对称的应答
 */
@Slf4j
@Component//springIOC容器中
public class MQProducerAckConfig implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnCallback {

    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private RedisTemplate redisTemplate;

    //实现 “包名+接口名”，使接口与当前类有关系
    //构造器执行，就执行init方法
    @PostConstruct
    public void init(){
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnCallback(this);
    }


    //交换机应答
    //应答时机：成功、失败 均应答
    @Override
    //boolean：交换机是否收到
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack) {
            System.out.println("交换机成功应答："+ cause);
        }else {
            System.out.println("交换机失败应答："+cause);
            //重新发送消息
            retrySendMessage(correlationData);
        }
    }

    //队列应答
    //应答时机：失败
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        //重新发送
        System.out.println("message:"+new String(message.getBody())+"replyCode:"+replyCode+"replyText:"+replyText+"exchange:"+exchange+"routingKey:"+routingKey);

        Object uuid = message.getMessageProperties().getHeader("spring_returned_message_correlation");
        //重新发送  次数
        String rabbit_prefix = (String)redisTemplate.opsForHash().get("rabbit_prefix",uuid);
        GmallCorrelationData gmallCorrelationData = JSONObject.parseObject(rabbit_prefix, GmallCorrelationData.class);

        //判断是否为插件的延迟消息
        if (gmallCorrelationData.isDelay()){
            return;
        }


        //retrySendMessage(gmallCorrelationData);
    }

    //重新发送      队列去交换机取消息，超出限定次数放弃取消息
    private void retrySendMessage(CorrelationData correlationData){
        GmallCorrelationData gmallCorrelationData = (GmallCorrelationData)correlationData;
        //重新发送2次
        int retryCount = gmallCorrelationData.getRetryCount();//默认 0次已发送
        retryCount++;
        gmallCorrelationData.setRetryCount(retryCount);
        if (retryCount <= 2) {
            //重新发送      发送给mq后，向下执行，多线程可能会出现先修改后两个发送成功的消息
            rabbitTemplate.convertAndSend(gmallCorrelationData.getExchange(),gmallCorrelationData.getRoutingKey(),
                    gmallCorrelationData.getMessage(),gmallCorrelationData);
            //更新redis中重发消息对象
            redisTemplate.opsForHash().put("rabbit_prefix",gmallCorrelationData.getId(),
                    JSONObject.toJSONString(gmallCorrelationData));
            log.info("成功重新发送："+JSONObject.toJSONString(gmallCorrelationData));
        }else {
            //打印日志
            log.info("剩余发送次数已用完："+JSONObject.toJSONString(gmallCorrelationData));
        }

    }
}
